﻿using BaseUtils.Helper;
using BaseUtils.Logger;
using Service.src.Flow.JavaScript;
using Service.src.Model.Folw;
using Service.src.NW.Enum;
using Service.src.NW.Model.Enum;
using Service.src.NW.Model;
using Service.src.NW.Model.Folw;
using System;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Service.src.NW.Processor.Core
{
    public class BaseProcessor
    {

        public static IBaseProcessor IBase;

        /// <summary>
        /// 获取入参值
        /// </summary>
        /// <param name="Node"></param>
        /// <param name="Param"></param>
        /// <returns></returns>
        [Obsolete("方法已过时，请使用 GetNodeInputParam ")]
        public static dynamic GetNodeInputParamValue(NodeProcessor Node, NodeDataSource Param)
        {
            if (Param == null)
            {
                SendNodeLoggerError(Node, $"参数配置异常 ", RuntimeErrorCodeEnum.NODE_INPUT_PARAM_NULL);
                return null;
            }
            dynamic v = null;
            if (Param.DataSource == DeviceTypeEnum.NODE)
            {
                if (!Node.ParentKeyValue.ContainsKey(Param.DataSourceId))
                {
                    SendNodeLoggerError(Node, $"节点{Node.id}参数引用异常，找不到入参id为{Param.DataSourceId}的对象", RuntimeErrorCodeEnum.NODE_INPUT_REFERENCE_EXCEPTION);
                    return v;
                }
                NodeProcessor Source = Node.ParentKeyValue[Param.DataSourceId];

                foreach (NodeDynamicInputOutParamBaseEntity Out in Source.NodeOutParam.OutParams)
                {
                    if (Param.ParamName == Out.ParamName)
                    {

                        try
                        {
                            if (Param.ParamName == NodeOutParamNameEnum.NODE_STATUS.ToString())
                            {
                                v = (int)Out.Value;
                            }
                            else
                            {
                                v = Out.Value;
                            }

                        }
                        catch (Exception ex)
                        {
                            SendNodeLoggerError(Node, "获取值异常:" + ex.Message, ex);
                        }
                        break;
                    }
                }
            }
            if (Param.DataSource == DeviceTypeEnum.GLOBAL_PARAM)
            {
                GlobalParamEntity _res = AppData.GlobalParams.Where(g => g.Id == Param.DataSourceId).FirstOrDefault();
                if (_res == null)
                {
                    SendNodeLoggerInfo(Node, $"节点{Node.id}中配置的全局变量{Param.DataSourceId}_{Param.ParamName}不存在");
                    return null;
                }
                v = _res.Value;
            }
            if (Param.DataSource == DeviceTypeEnum.CUSTOM_PARAM)
            {
                v = Param.ParamName;
            }
            return v;
        }

        /// <summary>
        /// 返回参数的值对象
        /// </summary>
        /// <param name="Node"></param>
        /// <param name="Param"></param>
        /// <returns></returns>
        public static NodeDataSource GetNodeInputParam(
            NodeProcessor Node,
            NodeDataSource Param)
        {
            if (Param == null|| Param.DataSource == DeviceTypeEnum.NULL)
            {
                SendNodeLoggerError(Node, $"参数配置异常 ", RuntimeErrorCodeEnum.NODE_INPUT_PARAM_NULL);
                return null;
            }
            dynamic v = null;
            if (Param.DataSource == DeviceTypeEnum.NODE)
            {
                if (!Node.ParentKeyValue.ContainsKey(Param.DataSourceId))
                {
                    SendNodeLoggerError(Node, $"节点{Node.id}参数引用异常，找不到入参id为{Param.DataSourceId}的对象", RuntimeErrorCodeEnum.NODE_INPUT_REFERENCE_EXCEPTION);
                    return v;
                }
                NodeProcessor Source = Node.ParentKeyValue[Param.DataSourceId];

                foreach (NodeDynamicInputOutParamBaseEntity Out in Source.NodeOutParam.OutParams)
                {
                    if (Param.ParamName == Out.ParamName)
                    {

                        try
                        {
                            if (Param.ParamName == NodeOutParamNameEnum.NODE_STATUS.ToString())
                            {
                                v = (int)Out.Value;
                            }
                            else
                            {
                                v = Out.Value;
                            }

                        }
                        catch (Exception ex)
                        {
                            SendNodeLoggerError(Node, "获取值异常:" + ex.Message, ex);
                        }
                        break;
                    }
                }
            }
            if (Param.DataSource == DeviceTypeEnum.GLOBAL_PARAM)
            {
                GlobalParamEntity _res = AppData.GlobalParams.Where(g => g.Id == Param.DataSourceId).FirstOrDefault();
                if (_res == null)
                {
                    SendNodeLoggerInfo(Node, $"节点{Node.id}中配置的全局变量{Param.DataSourceId}_{Param.ParamName}不存在");
                    return null;
                }
                v = _res.Value;
            }
            if (Param.DataSource == DeviceTypeEnum.CUSTOM_PARAM)
            {
                v = Param.ParamName;
            }
            Param.Value = v;
            return Param;
        }

        /// <summary>
        /// 设置输出参数的值
        /// </summary>
        /// <param name="Node"></param>
        /// <param name="Param"></param>
        /// <param name="Value"></param>
        public static void SetNodeOutParamValue(NodeProcessor Node, NodeOutParamNameEnum Param, dynamic Value)
        {
            foreach (NodeDynamicInputOutParamBaseEntity Out in Node.NodeOutParam.OutParams)
            {
                if (Out.ParamName == Param.ToString())
                {
                    if (Param == NodeOutParamNameEnum.NODE_STATUS)
                    {
                        Out.Value = (int)Value;
                    }
                    else
                    {
                        Out.Value = Value;
                    }
                    break;
                }
            }
            if (Param == NodeOutParamNameEnum.NODE_STATUS)
            {
                Node.NodeStatus = Value;
            }
            if (Param == NodeOutParamNameEnum.NODE_STATUS && Node.NodeStatus != NodeStatusEnum.STATIC_EXECUTION)
            {
                StringBuilder SB = new StringBuilder();
                foreach (NodeDynamicInputOutParamBaseEntity o in Node.NodeOutParam.OutParams)
                {
                    SB.AppendLine($"{o.ParamName}={o.Value}；");
                }
                SendNodeLoggerInfo(Node, $"节点输出值：{SB.ToString()}", Node.Code.ToString().ToEnum<RuntimeErrorCodeEnum>());
            }
        }

        public static void SetNodeOutParamValue(NodeProcessor Node, NodeDataSource TargetParam, dynamic Value)
        {
            SetNodeOutParamValue(Node, TargetParam.ParamName, Value);

            //foreach (NodeDynamicInputOutParamBaseEntity Out in Node.NodeOutParam.OutParams)
            //{
            //    //if (Out.ParamName == TargetParam.ParamName)
            //    //{
            //    //    Out.Value = Value;
            //    //}

            //}
            //string OutParams = Node.NodeOutParam.OutParams.ToJson();
        }

        public static void SetNodeOutParamValue(NodeProcessor Node, string OutParam, dynamic Value)
        {
            foreach (NodeDynamicInputOutParamBaseEntity Out in Node.NodeOutParam.OutParams)
            {
                if (Out.ParamName == OutParam)
                {
                    Out.Value = Value;
                }
            }
            //string OutParams = Node.NodeOutParam.OutParams.ToJson();
        }

        /// <summary>
        /// 给输出参数赋值，其他节点要使用才能获取
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Node"></param>
        /// <param name="t"></param>
        public static void SetNodeOutParamValue<T>(NodeProcessor Node, T t)
        {
            Type type = t.GetType();
            string ClassName = type.Name;
            PropertyInfo[] Fields = type.GetProperties();

            foreach (PropertyInfo item in Fields)
            {
                NodeDataSource source = new NodeDataSource();
                source.ParamName = $"{ClassName}.{item.Name}";
                SetNodeOutParamValue(Node, source, item.GetValue(t));
            }
        }

        //public static void SendNodeLogger(NodeLogger Logger)
        //{
        //    JavaScriptEvent.Send(JavaScriptEventEnum.NODE_LOGGER, Logger);
        //}

        public static void SendNodeLoggerInfo(NodeProcessor Node, string Message, RuntimeErrorCodeEnum Code = RuntimeErrorCodeEnum.IGNORE)
        {
            NodeLogger Logger = new NodeLogger(Message).Info();
            Logger.NodeId = Node.id;
            Logger.Code = (int)Code;

            JavaScriptEvent.Send(JavaScriptEventEnum.NODE_LOGGER, Logger);
        }

        public static void SendNodeLoggerWarning(NodeProcessor Node, string Message, RuntimeErrorCodeEnum Code = RuntimeErrorCodeEnum.IGNORE)
        {
            NodeLogger Logger = new NodeLogger(Message).Warning();
            Logger.NodeId = Node.id;
            Logger.Code = (int)Code;

            JavaScriptEvent.Send(JavaScriptEventEnum.NODE_LOGGER, Logger);
        }
        //public static void SendNodeLoggerWarning(NodeProcessor Node, string Message, Exception ex,
        //    RuntimeErrorCodeEnum Code = RuntimeErrorCodeEnum.IGNORE)
        //{
        //    NodeLogger Logger = new NodeLogger(Message).Warning();
        //    Logger.Code = (int)Code;
        //    Logger.NodeId = Node.id;

        //    JavaScriptEvent.Send(JavaScriptEventEnum.NODE_LOGGER, Logger);
        //}

        public static void SendNodeLoggerError(NodeProcessor Node, string Message, RuntimeErrorCodeEnum Code = RuntimeErrorCodeEnum.IGNORE)
        {
            SendNodeLoggerError(Node, Message, null, Code);
        }

        public static void SendNodeLoggerError(NodeProcessor Node, string Message, Exception ex,
            RuntimeErrorCodeEnum Code = RuntimeErrorCodeEnum.IGNORE)
        {
            NodeLogger Logger = new NodeLogger(Message).Error(ex);
            Logger.Code = (int)Code;
            Logger.NodeId = Node.id;

            JavaScriptEvent.Send(JavaScriptEventEnum.NODE_LOGGER, Logger);
        }

        private void SetCode(NodeProcessor Node, string Message, RuntimeErrorCodeEnum Code = RuntimeErrorCodeEnum.IGNORE)
        {
            Node.Logger = new NodeLogger(Message);
            Node.Code = (int)Code;
        }

        /// <summary>
        /// 执行节点完成事件
        /// </summary>
        /// <param name="Node"></param>
        public static void Complete(NodeProcessor Node, NodeStatusEnum nodeStatus = NodeStatusEnum.ERROR)
        {
            SetNodeOutParamValue(Node, NodeOutParamNameEnum.NODE_STATUS, nodeStatus);
            if (NodeComplete(Node))
            {
                if (Node.Children.Count <= 0)
                {
                    AppData.RemoveRunCompleteNodeId(Node._FlowId, Node.id);
                }
                // 递归执行子节点
                // LoggerService.Info($"正在执行节点：{id}，{name}");
                foreach (var child in Node.Children)
                {
                    Task.Run(() =>
                    {
                        try
                        {
                            if (child.NodeStatus != NodeStatusEnum.DEFAULT || AppData.RuningNodes[Node._FlowId].Contains(child.id))
                            {
                                return;
                            }
                        }
                        catch (Exception ex)
                        {
                            LoggerService.Info($"未知错误：{ex.Message}", ex);
                        }

                        if (Node.NodeStatus != NodeStatusEnum.STATIC_EXECUTION)
                        {
                            AppData.AddRuningNodeId(Node._FlowId, child.id);
                            LoggerService.Info($"执行当前节点：{child.id}，{child.name}");
                        }
                        Task _child = child.ExecuteNode(Node._FlowId);
                        if (_child.Status == TaskStatus.Faulted)
                        {
                            child.NodeStatus = NodeStatusEnum.ERROR;
                            string ExecuteNodeErrorMessage = _child.Exception?.ToString();
                            if (!string.IsNullOrEmpty(ExecuteNodeErrorMessage))
                            {
                                SendNodeLoggerError(child, ExecuteNodeErrorMessage);
                            }
                            Complete(child, NodeStatusEnum.ERROR);
                        }

                        AppData.RemoveRunCompleteNodeId(Node._FlowId, Node.id);
                    });
                }

            }
        }

        /// <summary>
        /// 节点执行结束
        /// </summary>
        /// <param name="Node"></param>
        public static bool NodeComplete(NodeProcessor Node)
        {
            if (Node.NodeStatus != NodeStatusEnum.STATIC_EXECUTION)
            {
                if (!Node.ExecutionSource.Task.IsCompleted)
                {
                    Node.ExecutionSource.SetResult(true);
                }

                Node.stopwatch.Stop();
                TimeSpan elapsedTime = Node.stopwatch.Elapsed;
                Node.NodeTotalSeconds = elapsedTime.TotalSeconds;
                if (Node.NodeStatus == NodeStatusEnum.SUCCESS)
                {
                    //Node.style.backgroundColor = "#0b9b0b";
                    Node.Logger = new NodeLogger($"节点完成！耗时: {elapsedTime.TotalSeconds} 秒").Info(ExceptionLevelEnum.Complete);
                }
                else
                {
                    //Node.style.backgroundColor = "#eb1b1b";
                    Node.Logger = new NodeLogger($"节点失败！节点id={Node.id}，耗时: {elapsedTime.TotalSeconds} 秒").Error();
                }
                Node.Logger.NodeId = Node.id;
                JavaScriptEvent.Send(JavaScriptEventEnum.NODE_LOGGER, Node.Logger);
                JavaScriptEvent.Send(JavaScriptEventEnum.NODE_COMPLETE, Node);
            }
            return Node.NodeStatus != NodeStatusEnum.DEFAULT;
        }
    }
}
